package theMemoryModel;

import classLoader.Test;

/**
 * @Author: Jamie Nie
 * @Date: 2021/6/22 15:50
 * @Slogan: The harder you work, the more luck you have.
 * @desc: 栈上分配，标量替换
 * 对象逃逸分析：就是分析对象动态作用域，当一个对象在方法中被定义后，它可能被外部方法所引用，例如作为调用参数传递到其他地方中。
 * 标量替换：通过逃逸分析确定该对象不会被外部访问，并且对象可以被进一步分解时，JVM不会创建该对象，而是将该对象成员变量分解若干个被这个方法使用的成员变量所代替，
 *         这些代替的成员变量在栈帧或寄存器上分配空间，这样就不会因为没有一大块连续空间导致对象内存不够分配。
 *
 *  标量与聚合量：标量即不可被进一步分解的量，而JAVA的基本数据类型就是标量（如：int，long等基本数据类型以及reference类型等），
 *             标量的对立就是可以被进一步分解的量，而这种量称之为聚合量。而在JAVA中对象就是可以被进一步分解的聚合量。
 *
 *  代码调用了1亿次alloc()，如果是分配到堆上，大概需要1GB以上堆空间，如果堆空间小于该值，必然会触发GC。
 *
 *  -XX:+DoEscapeAnalysis 开启逃逸分析（JDK7之后默认开启）
 *  -XX:+EliminateAllocations 开启标量替换（前提开启逃逸分析）
 *  -XX:+PrintGC 打印GC日志
 *
 *  使用如下参数不会发生GC (对象分配在栈内存中)
 *  -Xmx15m -Xms15m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:+EliminateAllocations
 *  使用如下参数都会发生大量GC (对象分配在堆内存中)
 *  -Xmx15m -Xms15m -XX:-DoEscapeAnalysis -XX:+PrintGC -XX:+EliminateAllocations
 *  -Xmx15m -Xms15m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-EliminateAllocations
 *
 *  栈上分配依赖于逃逸分析和标量替换
 */
public class AllotOnStack {
    public static void main(String[] args) {
        long beginTime = System.currentTimeMillis();
        for (int i=0;i<100000000;i++){
            alloc();
        }
        System.out.println("耗时：" + (System.currentTimeMillis() - beginTime) + " ms");
    }

    public static void alloc(){
        Test test = new Test();
        test.setAge(1);
        test.setName("Jamie");
    }
}
